#include "D3DEngine.h"
#include <algorithm>

D3DEngine::D3DEngine(HWND hWnd)
{
	d3d = Direct3DCreate9(D3D_SDK_VERSION);

	D3DPRESENT_PARAMETERS d3dpp;

	ZeroMemory(&d3dpp, sizeof(d3dpp));
	d3dpp.Windowed = TRUE;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.hDeviceWindow = hWnd;
	d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
	d3dpp.BackBufferWidth = SCREEN_WIDTH;
	d3dpp.BackBufferHeight = SCREEN_HEIGHT;
	d3dpp.EnableAutoDepthStencil = TRUE;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

	d3d->CreateDevice(D3DADAPTER_DEFAULT,
		D3DDEVTYPE_HAL,
		hWnd,
		D3DCREATE_SOFTWARE_VERTEXPROCESSING,
		&d3dpp,
		&d3ddev);

	d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE);
	d3ddev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
	d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE); 
	d3ddev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
	d3ddev->SetRenderState(D3DRS_ALPHAREF, (DWORD)0x00000001);
	d3ddev->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
	d3ddev->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);

	D3DXCreateSprite(d3ddev, &pSprite);
	D3DXCreateTextureFromFile(d3ddev, L"C:\\Users\\Aftiagouras\\Pictures\\star.png", &Default);

	std::vector<int*> piVector;
	int* a;
	piVector.push_back(a);
}

void D3DEngine::RenderFrame()
{
	d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);



	d3ddev->BeginScene();

	DrawSprites();

	d3ddev->EndScene();
	d3ddev->Present(NULL, NULL, NULL, NULL);
}

void D3DEngine::DrawSprites()
{
	pSprite->Begin(D3DXSPRITE_SORT_DEPTH_FRONTTOBACK);
	UINT nSprites = Sprites.size();
	Sprite* s;
	std::sort(Sprites.begin(), Sprites.end(), [](Sprite* a, Sprite* b){ return std::abs(a->level) < std::abs(b->level); });
	for (UINT i = 0; i < nSprites; i++)
	{
		s = Sprites[i];
		D3DXMATRIX ScalingMatrix;
		D3DXMATRIX RotationMatrix;
		D3DXMATRIX TranslationMatrix;
		D3DXMATRIX Product;

		D3DXMatrixScaling(&ScalingMatrix, s->scaleX, s->scaleY, 1.0f);
		D3DXMatrixRotationZ(&RotationMatrix, s->r);
		D3DXMatrixTranslation(&TranslationMatrix, s->x, s->y, .0f);
		D3DXMatrixMultiply(&Product, &ScalingMatrix, &RotationMatrix);
		D3DXMatrixMultiply(&Product, &Product, &TranslationMatrix);

		pSprite->SetTransform(&Product);

		D3DXVECTOR3 Center(s->Width / 2.0f, s->Height / 2.0f, 0.0f);

		if (s->Texture == NULL) pSprite->Draw(Default, NULL, new D3DXVECTOR3(50.0f, 50.0f, 0.0f), NULL, 0xFFFFFFFF);
		else pSprite->Draw(s->Texture, NULL, &Center, NULL, s->Color);
	}
	pSprite->End();
}

void D3DEngine::AddSprite(Sprite* s)
{
	Sprites.push_back(s);
}

void D3DEngine::RemoveSprite(Sprite* s)
{	
	Sprites.erase(std::find(Sprites.begin(), Sprites.end(), s));
}

Sprite D3DEngine::CreateSprite(LPCWSTR f)
{
	HRESULT hr;
	D3DSURFACE_DESC Desc;
	LPDIRECT3DTEXTURE9 pTexture;
	hr = D3DXCreateTextureFromFile(d3ddev, f, &pTexture);
	if (hr != D3D_OK) return Sprite();
	pTexture->GetLevelDesc(0, &Desc);
	return Sprite(Desc.Height, Desc.Width, pTexture);
}

void D3DEngine::Dispose()
{
	d3ddev->Release();
	d3d->Release();
}

Sprite::Sprite()
{
	Sprite(100, 100, NULL);
}

Sprite::Sprite(UINT h, UINT w, LPDIRECT3DTEXTURE9 t)
{
	Height = h;
	Width = w;
	Texture = t;
}

LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	HWND hWnd;
	WNDCLASSEX wc;
	int c = 0;

	Sprite Stars[200];
	float velocity=0;

	ZeroMemory(&wc, sizeof(WNDCLASSEX));

	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WindowProc;
	wc.hInstance = hInstance;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.lpszClassName = L"WindowClass";

	RegisterClassEx(&wc);

	hWnd = CreateWindowEx(NULL, L"WindowClass", L"Our Direct3D Program",
		WS_OVERLAPPEDWINDOW, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
		NULL, NULL, hInstance, NULL);

	ShowWindow(hWnd, nCmdShow);
	
	D3DEngine Engine(hWnd);
	MSG msg;

	for (int i = 0; i < 200; i++)
	{
		Stars[i] = Engine.CreateSprite(L"C:\\Users\\Aftiagouras\\Pictures\\star.png");
		Stars[i].r = ((rand() % 8) / 8.0f) * 3.14159f * 2.0f;
		Stars[i].scaleX = 0.5 + ((rand() % 100) / 200.0f);
		Stars[i].scaleY = Stars[i].scaleX;
		Stars[i].x = rand() % (SCREEN_WIDTH);
		Stars[i].y = rand() % (SCREEN_HEIGHT);
		Stars[i].Color = D3DCOLOR_ARGB(255, rand() % 255, rand() % 255, rand() % 255);
		Engine.AddSprite(&Stars[i]);
	}

	while (TRUE)
	{

		while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

		if (msg.message == WM_QUIT)
			break;

		/*if (msg.message == WM_KEYDOWN)
		{
			if (msg.wParam == VK_UP) velocity = 2.0f;
			if (msg.wParam == VK_DOWN) velocity = -2.0f;
			if (msg.wParam == VK_LEFT) Agent.r -= .1f;
			if (msg.wParam == VK_RIGHT) Agent.r += .1f;
		}

		if (msg.message == WM_KEYUP)
		{
			if (msg.wParam == VK_UP) velocity = 0;
			if (msg.wParam == VK_DOWN) velocity = -0;
		}
		Agent.x += velocity*cos(Agent.r);
		Agent.y += velocity*sin(Agent.r);*/

		for (int i = 0; i < 200; i++)
		{
			float newX = Stars[i].x + 4 * cos(Stars[i].r);
			float newY = Stars[i].y + 4 * sin(Stars[i].r);
			if (newX < 0 || newX > SCREEN_WIDTH) Stars[i].r = 3.14159f - Stars[i].r;
			if (newY < 0 || newY > SCREEN_HEIGHT) Stars[i].r = -Stars[i].r;
			Stars[i].x += 4 * cos(Stars[i].r);
			Stars[i].y += 4 * sin(Stars[i].r);
		}

		Engine.RenderFrame();
		c++;
	}

	Engine.Dispose();

	return msg.wParam;
}


// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_DESTROY:
	{
					   PostQuitMessage(0);
					   return 0;
	} break;
	}

	return DefWindowProc(hWnd, message, wParam, lParam);
}

